大家好,我是 Yubin
這篇文章要講的是 FastifyInstance 中定義的幾個重要 method。
大部分是用來設定伺服器的行為,以及註冊 plugins, routes, hooks 用。
listen
可以設定 fastify server 要聽在哪個 host、哪個 port 上,以及成功或失敗的處理。
import fastify, { FastifyInstance, FastifyListenOptions } from 'fastify'
const server: FastifyInstance = fastify()
const fastifyConfig: FastifyListenOptions = {
  port: 8888,
  host: '0.0.0.0'
}
server.listen(fastifyConfig, (error, address) => {
  if (error) {
    console.error(error)
  }
})
.listen() 方法第一個參數為 FastifyListenOptions 物件,常常用來設定這個 server 聽的 address 及 port。
如果沒有給定 host,則會聽在 localhost 上 (也就是只能接收本機來的 request)。
如果沒有給定 port,則會在系統中找第一個可以用的 port 來開。
值得注意的是,'0.0.0.0' 表示會聽所有 IPv4 的 request。
如果環境中可能會有 IPv6 的 request 進來,可以將 host 設定為 '::'。
const fastifyConfig: FastifyListenOptions = {
  port: 8888,
  host: '::'
}
所以如果自己在 local 測試都沒問題,部屬出去發現怎麼打不到,可能就是這個 host 的值沒有給定。
.ready()
若所有 plugins 都被載入完成會呼叫這個 function,若 plugins 載入過程有錯誤,會拋出錯誤。
可以用 callback 的寫法,如
server.ready(err => {
  if (err) throw err
})
.ready() 本身也是一個 Promise 物件,可以用這個方法來處理成功或失敗的情況。
server.ready().then(() => {
  console.log('successfully booted!')
}, (err) => {
  console.log('an error happened', err)
})
自己常用的寫法是 await server.ready() 來確保程式流程往下後,每個 plugins 都被載入成功。(因為有許多 plugin 的註冊都是 async function)
.after()
註冊完一個或多個 plugins 後呼叫,會在 .ready() 之前被呼叫。
可以用來對每個 plugin 的載入狀況做個別的處理。
server
  .register((instance, opts, done) => {
    console.log('Current plugin')
    done()
  })
  .after(err => {
    console.log('After current plugin')
  })
  .register((instance, opts, done) => {
    console.log('Next plugin')
    done()
  })
  .ready(err => {
    console.log('Everything has been loaded')
  })
.route()
註冊 route 用的,裡面傳入 RouteOptions 物件。更多資訊可以參考 Fastify101: route。
.hasRoute()
用來檢查某個 route 是否存在,回傳值為 boolean。
const routeExists = server.hasRoute({
  url: '/',
  method: 'GET'
})
if (routeExists === false) {
  // add route
}
.close()
將 FastifyInstance 關閉用。
server 關閉的途中,如果有新的 request 進來,會回應 503 (Service Unavailable) 的狀態碼,並將該 request 銷毀。
如果需要,可以控制 FastifyServerOptions 中的 return503OnClosing 來改變預設行為。
.close() 本身也是一個 Promise 物件,可以處理正常關閉或錯誤關閉的情況。
fastify.close().then(() => {
  console.log('successfully closed!')
}, (err) => {
  console.log('an error happened', err)
})
.addHook()
註冊 hook 使用。
.register()
註冊 plugin 使用。
.log
這個不是 function,.log 可以拿到 logger 的 instance,預設為 Pino instance,用來寫 log 非常方便。
server.log.info('Hello Pino')
.inject()
製造一個假的 request 傳入 server 中,寫 server 的 testing 的時候必備。
.setNotFoundHandler()
設定 404 Not Found 時候的處理行為。
.setErrorHandler()
Fastify 預設會將 error 的處理以狀態碼 500 (Internal Server Error) 的形式回應出去,這個 handler 可以控制這個預設行為。
例如,收到 error 的時候寫 log,或改變預設的 Status Code。
server.setErrorHandler((error, request, reply) => {
  // Log error
  request.log.error(error)
  // Send error response
  reply.status(409).send({ ok: false })
})
.printRoutes()
印出 route 的樹狀圖,debug 很好用。
記得要在 .reader() 之後 (或 callback) 中使用。
server.get('/test', () => {})
server.get('/test/hello', () => {})
server.get('/hello/world', () => {})
server.get('/helicopter', () => {})
server.ready(() => {
  console.log(server.printRoutes())
})
印出
└── /
    ├── test (GET)
    │   test (HEAD)
    │   └── /hello (GET)
    │       /hello (HEAD)
    └── hel
        ├── lo
        │   └── /world (GET)
        │       /world (HEAD)
        └── icopter (GET)
            icopter (HEAD)
可以加上 commonPrefix: false 的參數。
console.log(server.printRoutes({ commonPrefix: false }))
└── / (-)
    ├── helicopter (GET, HEAD)
    ├── hello/world (GET, HEAD)
    └── test (GET, HEAD)
        └── /hello (GET, HEAD)
.printPlugins()
可以把所有註冊的 plugins 印出來,一樣 debug 用。
以上是常用/實用的 Fastify Server Methods。
如果想要了解更多資訊,可以參考 Fastify: Server Method。